﻿using System.Drawing;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.Reflection;
using System.Collections.Generic;
using System;

namespace Marbles.Core.Content.FileSystem
{
    public static class Icons
    {
        struct SHFILEINFO
        {
            public IntPtr hIcon;
            public IntPtr iIcon;
            public uint dwAttributes;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string szDisplayName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
            public string szTypeName;
        };

        [Flags]
        enum FileInfoFlags : int
        {
            SHGFI_ICON = 0x000000100,
            SHGFI_USEFILEATTRIBUTES = 0x000000010
        }

        [DllImport("Shell32", CharSet = CharSet.Auto)]
        extern static int ExtractIconEx(
        [MarshalAs(UnmanagedType.LPTStr)] 
            string lpszFile,
        int nIconIndex,
        IntPtr[] phIconLarge,
        IntPtr[] phIconSmall,
        int nIcons);

        [DllImport("Shell32", CharSet = CharSet.Auto)]
        extern static IntPtr SHGetFileInfo(
        string pszPath,
        int dwFileAttributes,
        out SHFILEINFO psfi,
        int cbFileInfo,
        FileInfoFlags uFlags);

        public enum SystemIconSize : int
        {
            Large = 0x000000000,
            Small = 0x000000001
        }
        
        static int GetIconsCountInFile(string fileName)
        {
            return ExtractIconEx(fileName, -1, null, null, 0);
        }

        public static void ExtractEx(string fileName, List<Icon> largeIcons, List<Icon> smallIcons, int firstIconIndex, int iconCount)
        {
            IntPtr[] smallIconsPtrs = null;
            IntPtr[] largeIconsPtrs = null;

            if (smallIcons != null)
            {
                smallIconsPtrs = new IntPtr[iconCount];
            }
            if (largeIcons != null)
            {
                largeIconsPtrs = new IntPtr[iconCount];
            }

            int apiResult = ExtractIconEx(fileName, firstIconIndex, largeIconsPtrs, smallIconsPtrs, iconCount);
            if (apiResult != iconCount)
            {
                return;
            }

            if (smallIcons != null)
            {
                smallIcons.Clear();
                foreach (IntPtr actualIconPtr in smallIconsPtrs)
                {
                    smallIcons.Add(Icon.FromHandle(actualIconPtr));
                }
            }
            if (largeIcons != null)
            {
                largeIcons.Clear();
                foreach (IntPtr actualIconPtr in largeIconsPtrs)
                {
                    largeIcons.Add(Icon.FromHandle(actualIconPtr));
                }
            }
        }

        public static List<Icon> ExtractEx(string fileName, SystemIconSize size,
        int firstIconIndex, int iconCount)
        {
            List<Icon> iconList = new List<Icon>();

            switch (size)
            {
                case SystemIconSize.Large:
                    ExtractEx(fileName, iconList, null, firstIconIndex, iconCount);
                    break;

                case SystemIconSize.Small:
                    ExtractEx(fileName, null, iconList, firstIconIndex, iconCount);
                    break;

            }

            return iconList;
        }

        public static void Extract(string fileName, List<Icon> largeIcons, List<Icon> smallIcons)
        {
            int iconCount = GetIconsCountInFile(fileName);
            ExtractEx(fileName, largeIcons, smallIcons, 0, iconCount);
        }

        public static List<Icon> Extract(string fileName, SystemIconSize size)
        {
            int iconCount = GetIconsCountInFile(fileName);
            return ExtractEx(fileName, size, 0, iconCount);
        }

        public static Icon ExtractOne(string fileName, int index, SystemIconSize size)
        {
            List<Icon> iconList = ExtractEx(fileName, size, index, 1);
            return iconList[0];
        }

        public static void ExtractOne(string fileName, int index, out Icon largeIcon, out Icon smallIcon)
        {
            List<Icon> smallIconList = new List<Icon>();
            List<Icon> largeIconList = new List<Icon>();
            ExtractEx(fileName, largeIconList, smallIconList, index, 1);
            largeIcon = largeIconList[0];
            smallIcon = smallIconList[0];
        }

        public static Icon IconFromExtension(string extension, SystemIconSize size)
        {
            if (extension[0] != '.') extension = '.' + extension;
            RegistryKey Root = Registry.ClassesRoot;
            RegistryKey ExtensionKey = Root.OpenSubKey(extension);
            ExtensionKey.GetValueNames();
            RegistryKey ApplicationKey =
            Root.OpenSubKey(ExtensionKey.GetValue("").ToString());
            string IconLocation = ApplicationKey.OpenSubKey("DefaultIcon").GetValue("").ToString();
            string[] IconPath = IconLocation.Split(',');

            if (IconPath[1] == null) IconPath[1] = "0";
            IntPtr[] Large = new IntPtr[1], Small = new IntPtr[1];
            ExtractIconEx(IconPath[0],
            Convert.ToInt16(IconPath[1]), Large, Small, 1);
            return size == SystemIconSize.Large ?
            Icon.FromHandle(Large[0]) : Icon.FromHandle(Small[0]);
        }

        public static Icon IconFromExtensionShell(string extension, SystemIconSize size)
        {
            if (extension[0] != '.') extension = '.' + extension;
            SHFILEINFO fileInfo = new SHFILEINFO();
            SHGetFileInfo(extension, 0, out fileInfo, Marshal.SizeOf(fileInfo), FileInfoFlags.SHGFI_ICON | FileInfoFlags.SHGFI_USEFILEATTRIBUTES | (FileInfoFlags)size);
            return Icon.FromHandle(fileInfo.hIcon);
        }

        public static Icon IconFromResource(string resourceName)
        {
            Assembly assembly = Assembly.GetCallingAssembly();
            return new Icon(assembly.GetManifestResourceStream(resourceName));
        }

        public static void ExtractInformationsFromRegistryString(string regString, out string fileName, out int index)
        {
            index = 0;
            string[] strArr = regString.Replace("\"", "").Split(',');
            fileName = strArr[0].Trim();
            if (strArr.Length > 1)
            {
                int.TryParse(strArr[1].Trim(), out index);
            }
        }

        public static Icon ExtractFromRegistryString(string regString, SystemIconSize size)
        {
            string fileName;
            int index;
            ExtractInformationsFromRegistryString(regString, out fileName, out index);
            return ExtractOne(fileName, index, size);
        }
    }
}
